﻿using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Data;
using System.Data.SqlTypes;
using System.Data.SqlClient;
using System.Collections.Generic;
using System.Reflection;
using System.Collections;
using System.Globalization;
using System.ComponentModel;
using System.Security;
using System.Security.Cryptography;
using System.Runtime;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;

using Microsoft.SqlServer.Server;

namespace PickGold.SqlServer
{
	/// <summary>
	/// Text
	/// </summary>
	public static class Text
	{
		#region Parse any

		/// <summary/>
		[SqlFunction(IsDeterministic = true, IsPrecise = false)]
		public static SqlBoolean ParseBoolean(SqlString input)
		{
			if (input.IsNull)
				return SqlBoolean.Null;

			var t = input.Value;
			if (string.IsNullOrEmpty(t))
				return SqlBoolean.Null;

			var v = false;
			if (bool.TryParse(t, out v))
				return v;

			return SqlBoolean.Null;
		}

		/// <summary/>
		[SqlFunction(IsDeterministic = true, IsPrecise = false)]
		public static SqlByte ParseByte(SqlString input, SqlString style)
		{
			if (input.IsNull)
				return SqlByte.Null;

			var t = input.Value;
			if (string.IsNullOrEmpty(t))
				return SqlByte.Null;

			var v = byte.MinValue;
			var s = style.IsNull ? null : style.Value;
			if (string.IsNullOrEmpty(style.Value))
			{
				if (byte.TryParse(t, out v))
					return v;

				return SqlByte.Null;
			}

			var si = int.MinValue;
			var sv = NumberStyles.None;
			if (int.TryParse(s, out si))
				sv = (NumberStyles)si;
			else if (s[0] == 'x' || s[0] == 'X')//(string.Compare(s, "x", StringComparison.OrdinalIgnoreCase) == 0)//
				sv = NumberStyles.HexNumber;
			else
				sv = (NumberStyles)Enum.Parse(typeof(NumberStyles), s, true);
			if (byte.TryParse(t, sv, null, out v))
				return v;

			return SqlByte.Null;
		}

		/// <summary/>
		[SqlFunction(IsDeterministic = true, IsPrecise = false)]
		public static SqlInt16 ParseInt16(SqlString input, SqlString style)
		{
			if (input.IsNull)
				return SqlInt16.Null;

			var t = input.Value;
			if (string.IsNullOrEmpty(t))
				return SqlInt16.Null;

			var v = short.MinValue;
			var s = style.IsNull ? null : style.Value;
			if (string.IsNullOrEmpty(style.Value))
			{
				if (short.TryParse(t, out v))
					return v;

				return SqlInt16.Null;
			}

			var si = int.MinValue;
			var sv = NumberStyles.None;
			if (int.TryParse(s, out si))
				sv = (NumberStyles)si;
			else if (s[0] == 'x' || s[0] == 'X')//(string.Compare(s, "x", StringComparison.OrdinalIgnoreCase) == 0)//
				sv = NumberStyles.HexNumber;
			else
				sv = (NumberStyles)Enum.Parse(typeof(NumberStyles), s, true);
			if (short.TryParse(t, sv, null, out v))
				return v;

			return SqlInt16.Null;
		}

		/// <summary/>
		[SqlFunction(IsDeterministic = true, IsPrecise = false)]
		public static SqlInt32 ParseInt32(SqlString input, SqlString style)
		{
			if (input.IsNull)
				return SqlInt32.Null;

			var t = input.Value;
			if (string.IsNullOrEmpty(t))
				return SqlInt32.Null;

			var v = int.MinValue;
			var s = style.IsNull ? null : style.Value;
			if (string.IsNullOrEmpty(style.Value))
			{
				if (int.TryParse(t, out v))
					return v;

				return SqlInt32.Null;
			}

			var si = int.MinValue;
			var sv = NumberStyles.None;
			if (int.TryParse(s, out si))
				sv = (NumberStyles)si;
			else if (s[0] == 'x' || s[0] == 'X')//(string.Compare(s, "x", StringComparison.OrdinalIgnoreCase) == 0)//
				sv = NumberStyles.HexNumber;
			else
				sv = (NumberStyles)Enum.Parse(typeof(NumberStyles), s, true);
			if (int.TryParse(t, sv, null, out v))
				return v;

			return SqlInt32.Null;
		}

		/// <summary/>
		[SqlFunction(IsDeterministic = true, IsPrecise = false)]
		public static SqlInt64 ParseInt64(SqlString input, SqlString style)
		{
			if (input.IsNull)
				return SqlInt64.Null;

			var t = input.Value;
			if (string.IsNullOrEmpty(t))
				return SqlInt64.Null;

			var v = long.MinValue;
			var s = style.IsNull ? null : style.Value;
			if (string.IsNullOrEmpty(style.Value))
			{
				if (long.TryParse(t, out v))
					return v;

				return SqlInt64.Null;
			}

			var si = int.MinValue;
			var sv = NumberStyles.None;
			if (int.TryParse(s, out si))
				sv = (NumberStyles)si;
			else if (s[0] == 'x' || s[0] == 'X')//(string.Compare(s, "x", StringComparison.OrdinalIgnoreCase) == 0)//
				sv = NumberStyles.HexNumber;
			else
				sv = (NumberStyles)Enum.Parse(typeof(NumberStyles), s, true);
			if (long.TryParse(t, sv, null, out v))
				return v;

			return SqlInt64.Null;
		}

		/// <summary/>
		[SqlFunction(IsDeterministic = true)]
		public static SqlSingle ParseSingle(SqlString input, SqlString style)
		{
			if (input.IsNull)
				return SqlSingle.Null;

			var t = input.Value;
			if (string.IsNullOrEmpty(t))
				return SqlSingle.Null;

			var v = float.MinValue;
			var s = style.IsNull ? null : style.Value;
			if (string.IsNullOrEmpty(style.Value))
			{
				if (float.TryParse(t, out v))
					return v;

				return SqlSingle.Null;
			}

			var si = int.MinValue;
			var sv = NumberStyles.None;
			if (int.TryParse(s, out si))
				sv = (NumberStyles)si;
			else if (s[0] == 'x' || s[0] == 'X')//(string.Compare(s, "x", StringComparison.OrdinalIgnoreCase) == 0)//
				sv = NumberStyles.HexNumber;
			else
				sv = (NumberStyles)Enum.Parse(typeof(NumberStyles), s, true);
			if (float.TryParse(t, sv, null, out v))
				return v;

			return SqlSingle.Null;
		}

		/// <summary/>
		[SqlFunction(IsDeterministic = true)]
		public static SqlDouble ParseDouble(SqlString input, SqlString style)
		{
			if (input.IsNull)
				return SqlDouble.Null;

			var t = input.Value;
			if (string.IsNullOrEmpty(t))
				return SqlDouble.Null;

			var v = double.MinValue;
			var s = style.IsNull ? null : style.Value;
			if (string.IsNullOrEmpty(style.Value))
			{
				if (double.TryParse(t, out v))
					return v;

				return SqlDouble.Null;
			}

			var si = int.MinValue;
			var sv = NumberStyles.None;
			if (int.TryParse(s, out si))
				sv = (NumberStyles)si;
			else if (s[0] == 'x' || s[0] == 'X')//(string.Compare(s, "x", StringComparison.OrdinalIgnoreCase) == 0)//
				sv = NumberStyles.HexNumber;
			else
				sv = (NumberStyles)Enum.Parse(typeof(NumberStyles), s, true);
			if (double.TryParse(t, sv, null, out v))
				return v;

			return SqlDouble.Null;
		}

		/// <summary/>
		[SqlFunction(IsDeterministic = true, IsPrecise = false)]
		public static SqlDecimal ParseDecimal(SqlString input, SqlString style)
		{
			if (input.IsNull)
				return SqlDecimal.Null;

			var t = input.Value;
			if (string.IsNullOrEmpty(t))
				return SqlDecimal.Null;

			var v = decimal.MinValue;
			var s = style.IsNull ? null : style.Value;
			if (string.IsNullOrEmpty(style.Value))
			{
				if (decimal.TryParse(t, out v))
					return v;

				return SqlDecimal.Null;
			}

			var si = int.MinValue;
			var sv = NumberStyles.None;
			if (int.TryParse(s, out si))
				sv = (NumberStyles)si;
			else if (s[0] == 'x' || s[0] == 'X')//(string.Compare(s, "x", StringComparison.OrdinalIgnoreCase) == 0)//
				sv = NumberStyles.HexNumber;
			else
				sv = (NumberStyles)Enum.Parse(typeof(NumberStyles), s, true);
			if (decimal.TryParse(t, sv, null, out v))
				return v;

			return SqlDecimal.Null;
		}

		/// <summary/>
		[SqlFunction(IsDeterministic = true, IsPrecise = false)]
		public static SqlDateTime ParseDateTime(SqlString input, SqlString style)
		{
			if (input.IsNull)
				return SqlDateTime.Null;

			var t = input.Value;
			if (string.IsNullOrEmpty(t))
				return SqlDateTime.Null;

			var v = DateTime.MinValue;
			var s = style.IsNull ? null : style.Value;
			if (string.IsNullOrEmpty(style.Value))
			{
				if (DateTime.TryParse(t, out v))
					return v;

				return SqlDateTime.Null;
			}

			var si = int.MinValue;
			var sv = DateTimeStyles.None;
			if (int.TryParse(s, out si))
				sv = (DateTimeStyles)si;
			else
				sv = (DateTimeStyles)Enum.Parse(typeof(DateTimeStyles), s, true);
			if (DateTime.TryParse(t, null, sv, out v))
				return v;

			return SqlDateTime.Null;
		}

		/// <summary/>
		[SqlFunction(IsDeterministic = true, IsPrecise = false)]
		public static SqlGuid ParseGuid(SqlString input)
		{
			if (input.IsNull)
				return SqlGuid.Null;

			var t = input.Value;
			if (string.IsNullOrEmpty(t))
				return SqlGuid.Null;

			try
			{
				//return new SqlGuid(t);
				return SqlGuid.Parse(t);
			}
			catch { }
			//catch (Exception x)
			//{
			//    //return SqlGuid.Null;
			//    throw new Exception("[" + t + "] " + x.Message, x);
			//}
			return SqlGuid.Null;
		}

		#endregion

		/// <summary>
		/// EncodingString
		/// </summary>
		/// <param name="data">data</param>
		/// <returns>SqlString</returns>
		[SqlFunction(IsDeterministic = true, IsPrecise = false)]
		public static SqlString Trim(SqlString data)
		{
			if (data.IsNull)
				return data;

			var t = data.Value;
			if (string.IsNullOrEmpty(t))
				return data;

			return new SqlString(data.Value.Trim());
		}

		/// <summary>
		/// EncodingString
		/// </summary>
		/// <param name="data">data</param>
		/// <param name="encoding">encoding</param>
		/// <returns>SqlString</returns>
		[SqlFunction(IsDeterministic = true, IsPrecise = false)]
		public static SqlString EncodingString(SqlBinary data, SqlString encoding)
		{
			if (encoding.IsNull || string.IsNullOrEmpty(encoding.Value))
				return new SqlString(Encoding.Default.GetString(data.Value));

			return new SqlString(Encoding.GetEncoding(encoding.Value).GetString(data.Value));
		}

		/// <summary>
		/// EncodingBinary
		/// </summary>
		/// <param name="data">data</param>
		/// <param name="encoding">encoding</param>
		/// <returns>SqlBinary</returns>
		[SqlFunction(IsDeterministic = true, IsPrecise = false)]
		public static SqlBinary EncodingBinary(SqlString data, SqlString encoding)
		{
			if (encoding.IsNull || string.IsNullOrEmpty(encoding.Value))
				return new SqlBinary(Encoding.Default.GetBytes(data.Value));

			return new SqlBinary(Encoding.GetEncoding(encoding.Value).GetBytes(data.Value));
		}

		/// <summary>
		/// EncodingBinaryCount
		/// </summary>
		/// <param name="data">data</param>
		/// <param name="encoding">encoding</param>
		/// <returns>SqlInt32</returns>
		[SqlFunction(IsDeterministic = true, IsPrecise = false)]
		public static SqlInt32 EncodingBinaryCount(SqlString data, SqlString encoding)
		{
			if (encoding.IsNull || string.IsNullOrEmpty(encoding.Value))
				return new SqlInt32(Encoding.Default.GetByteCount(data.Value));

			return new SqlInt32(Encoding.GetEncoding(encoding.Value).GetByteCount(data.Value));
		}

		private static void FillRowSplit(object item, out SqlString result)
		{
			result = new SqlString(item as string);
		}

		/// <summary>
		/// Split
		/// </summary>
		/// <param name="data">data</param>
		/// <param name="separator">separator</param>
		/// <returns>IEnumerable</returns>
		[SqlFunction(IsDeterministic = true, IsPrecise = false, FillRowMethodName = "FillRowSplit", TableDefinition = "[result] [nvarchar](MAX)")]
		[Description("分割字符串")]
		[return: Description("分割后的结果，已忽略空白项")]
		public static IEnumerable Split([Description("要分割字符串")]SqlString data, [Description("分割符")]SqlString separator)
		{
			if (data.IsNull)
				return null;

			if (separator.IsNull || string.IsNullOrEmpty(separator.Value) || string.IsNullOrEmpty(data.Value))
				return new string[] { data.Value };

			return data.Value.Split(new string[] { separator.Value }, StringSplitOptions.None);
		}

		private static Regex GetRegex(SqlString pattern)
		{
			if (pattern.IsNull || string.IsNullOrEmpty(pattern.Value))
				return null;

			if (pattern.Value[0] != '/')
				return null;

			var ro = RegexOptions.None;
			for (var i = pattern.Value.Length - 1; i >= 0; i--)
			{
				switch (pattern.Value[i])
				{
					case 'i':
					case 'I':
						ro |= RegexOptions.IgnoreCase;
						break;
					case 'm':
					case 'M':
						ro |= RegexOptions.Multiline;
						break;
					case 'g':
					case 'G':
						ro |= RegexOptions.Compiled;
						break;
					case '/':
						return new Regex(pattern.Value.Substring(1, i - 1), ro);//"/123456789/img"
					default:
						return null;
				}
			}

			return null;// new Regex(pattern.Value, ro);
		}

		private static void FillRowRegex(object data, out SqlString value, out SqlInt32 index, out SqlInt32 length, out SqlBoolean success, out SqlInt32 match, out SqlInt32 group)
		{
			var g = data as Group;
			if (g != null)
			{
				value = new SqlString(g.Value);
				index = new SqlInt32(g.Index);
				length = new SqlInt32(g.Length);
				success = new SqlBoolean(g.Success);
				match = new SqlInt32(-1);
				group = new SqlInt32(-1);
				return;
			}

			var os = data as object[];
			if (os != null && os.Length == 6)
			{
				value = new SqlString((string)os[2]);
				index = new SqlInt32((int)os[3]);
				length = new SqlInt32((int)os[4]);
				success = new SqlBoolean((bool)os[5]);
				match = new SqlInt32((int)os[0]);
				group = new SqlInt32((int)os[1]);
				return;
			}

			value = null;
			index = new SqlInt32(-1);
			length = new SqlInt32(-1);
			success = new SqlBoolean(false);
			match = new SqlInt32(-1);
			group = new SqlInt32(-1);
		}

		/// <summary>
		/// RegexTest
		/// </summary>
		/// <param name="data">SqlString</param>
		/// <param name="pattern">SqlString</param>
		/// <returns>SqlBoolean</returns>
		[SqlFunction(IsDeterministic = true, IsPrecise = false)]
		[Description("检测字符串是否满足指定的正则模式")]
		public static SqlBoolean RegexTest([Description("要检测的字符串")]SqlString data, [Description("正则（i=不分大小写；m=多行；g=全局预编译）模式：/pattern/img")]SqlString pattern)
		{
			if (data.IsNull)
				return new SqlBoolean(false);

			var regex = GetRegex(pattern);
			if (regex == null || string.IsNullOrEmpty(data.Value))
				return new SqlBoolean(false);

			return new SqlBoolean(regex.IsMatch(data.Value));
		}

		/// <summary>
		/// RegexReplace
		/// </summary>
		/// <param name="data">SqlString</param>
		/// <param name="pattern">SqlString</param>
		/// <param name="replacement">SqlString</param>
		/// <returns>SqlBoolean</returns>
		[SqlFunction(IsDeterministic = true, IsPrecise = false)]
		[Description("正则替换")]
		public static SqlString RegexReplace([Description("要替换的字符串")]SqlString data, [Description("正则（i=不分大小写；m=多行；g=全局预编译）模式：/pattern/img")]SqlString pattern, [Description("替换模式($1$2）字符串")]SqlString replacement)
		{
			if (data.IsNull)
				return data;

			var regex = GetRegex(pattern);
			if (regex == null || string.IsNullOrEmpty(data.Value))
				return data;

			if (replacement.IsNull)
				return new SqlString(regex.Replace(data.Value, string.Empty));

			return new SqlString(regex.Replace(data.Value, replacement.Value));
		}

		/// <summary>
		/// RegexMatch
		/// </summary>
		/// <param name="data">SqlString</param>
		/// <param name="pattern">SqlString</param>
		/// <returns>SqlBoolean</returns>
		[SqlFunction(IsDeterministic = true, IsPrecise = false, FillRowMethodName = "FillRowRegex", TableDefinition = "[value] [nvarchar](MAX) NULL, [index] [int]/* NOT NULL*/, [length] [int]/* NOT NULL*/, [success] [bit]/* NOT NULL*/, [match] [int]/* NOT NULL*/, [group] [int]/* NOT NULL*/")]
		[Description("正则匹配分析")]
		public static IEnumerable RegexMatch([Description("要匹配分析的字符串")]SqlString data, [Description("正则（i=不分大小写；m=多行；g=全局预编译）模式：/pattern/img")]SqlString pattern)
		{
			if (data.IsNull)
				return null;

			var regex = GetRegex(pattern);
			if (regex == null || string.IsNullOrEmpty(data.Value))
				return null;

			//return regex.Match(data.Value).Groups;
			var match = regex.Match(data.Value);
			var os = new object[match.Groups.Count][];
			for (var i = 0; i < os.Length; i++)
			{
				os[i] = new object[6];
				os[i][0] = -1;
				os[i][1] = i;
				os[i][2] = match.Groups[i].Value;
				os[i][3] = match.Groups[i].Index;
				os[i][4] = match.Groups[i].Length;
				os[i][5] = match.Groups[i].Success;
			}
			return os;
		}

		/// <summary>
		/// RegexMatchValue
		/// </summary>
		/// <param name="data">SqlString</param>
		/// <param name="pattern">SqlString</param>
		/// <param name="match">SqlInt32</param>
		/// <param name="group">SqlInt32</param>
		/// <returns>SqlString</returns>
		[SqlFunction(IsDeterministic = true, IsPrecise = false)]
		[Description("取指定正则匹配的数据值")]
		public static SqlString RegexMatchValue([Description("要匹配分析的字符串")]SqlString data, [Description("正则（i=不分大小写；m=多行；g=全局预编译）模式：/pattern/img")]SqlString pattern, [Description("匹配索引")]SqlInt32 match, [Description("分组索引")]SqlInt32 group)
		{
			if (data.IsNull)
				return null;

			var regex = GetRegex(pattern);
			if (regex == null || string.IsNullOrEmpty(data.Value))
				return null;

			if (!match.IsNull && match.Value > 0)
				return new SqlString(regex.Matches(data.Value)[match.Value].Groups[group.IsNull ? 0 : group.Value].Value);

			return new SqlString(regex.Match(data.Value).Groups[group.IsNull ? 0 : group.Value].Value);
		}

		/// <summary>
		/// RegexMatches
		/// </summary>
		/// <param name="data">SqlString</param>
		/// <param name="pattern">SqlString</param>
		/// <returns>SqlBoolean</returns>
		[SqlFunction(IsDeterministic = true, IsPrecise = false, FillRowMethodName = "FillRowRegex", TableDefinition = "[value] [nvarchar](MAX) NULL, [index] [int]/* NOT NULL*/, [length] [int]/* NOT NULL*/, [success] [bit]/* NOT NULL*/, [match] [int]/* NOT NULL*/, [group] [int]/* NOT NULL*/")]
		[Description("正则匹配分析")]
		public static IEnumerable RegexMatches([Description("要匹配分析的字符串")]SqlString data, [Description("正则（i=不分大小写；m=多行；g=全局预编译）模式：/pattern/img")]SqlString pattern)
		{
			if (data.IsNull)
				return null;

			var regex = GetRegex(pattern);
			if (regex == null || string.IsNullOrEmpty(data.Value))
				return null;

			var ls = new List<object[]>();
			var matches = regex.Matches(data.Value);
			for (var i = 0; i < matches.Count; i++)
			{
				for (var ii = 0; ii < matches[i].Groups.Count; ii++)
				{
					var os = new object[6];
					os[0] = i;
					os[1] = ii;
					os[2] = matches[i].Groups[ii].Value;
					os[3] = matches[i].Groups[ii].Index;
					os[4] = matches[i].Groups[ii].Length;
					os[5] = matches[i].Groups[ii].Success;
					ls.Add(os);
				}
			}
			return ls;
		}

		/// <summary>
		/// Split
		/// </summary>
		/// <param name="data">data</param>
		/// <param name="pattern">separator</param>
		/// <returns>IEnumerable</returns>
		[SqlFunction(IsDeterministic = true, IsPrecise = false, FillRowMethodName = "FillRowSplit", TableDefinition = "[result] [nvarchar](MAX)")]
		[Description("正则分割字符串")]
		public static IEnumerable RegexSplit([Description("要分割的字符串")]SqlString data, [Description("正则（i=不分大小写；m=多行；g=全局预编译）模式：/pattern/img")]SqlString pattern)
		{
			if (data.IsNull)
				return null;

			var regex = GetRegex(pattern);
			if (regex == null || string.IsNullOrEmpty(data.Value))
				return new string[] { data.Value };

			return regex.Split(data.Value);
		}

		private static void FillRowLike(object item, out SqlString value, out SqlInt32 match, out SqlInt32 index)
		{
			if (item == null)
			{
				value = SqlString.Null;
				match = SqlInt32.Null;
				index = SqlInt32.Null;
				return;
			}

			var os = item as object[];
			if (os == null || os.Length != 3)
			{
				value = SqlString.Null;
				match = SqlInt32.Null;
				index = SqlInt32.Null;
				return;
			}

			value = new SqlString(os[0] as string);
			match = new SqlInt32((int)os[1]);
			index = new SqlInt32((int)os[2]);
		}

		/// <summary>
		/// 分割以空格分隔的搜索字符串
		/// </summary>
		/// <param name="data">要分割的字符串，加减号表现在match中，引号表示完整关键词</param>
		/// <returns>对象数据object[]{value, match, index}</returns>
		[SqlFunction(IsDeterministic = true, IsPrecise = false, FillRowMethodName = "FillRowLike", TableDefinition = "[value] [nvarchar](MAX) NULL, [match] [int]/* NOT NULL*/, [index] [int]/* NOT NULL*/")]
		[Description("分割以空格分隔的搜索字符串")]
		public static IEnumerable SplitSearch([Description("要分割的字符串，加减号前缀表现在match中，引号表示完整关键词")]this string data)
		{
			return data.InnerSplitSearch((a, b, c, d) => new object[] { c, b, a, }, null);
		}

		/// <summary>
		/// 分割以空格分隔的搜索字符串
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <param name="data">参数，用空格或制表符分割的字符串，如：aaa +bbb -ccc !ddd +"eee's eee" -"ffff"ff"</param>
		/// <param name="callback">T callback(int index, int match, string value, object state)</param>
		/// <param name="state"></param>
		/// <returns></returns>
		public static IEnumerable<T> InnerSplitSearch<T>(this string data, Func<int, int, string, object, T> callback, object state)
		{
			if (string.IsNullOrEmpty(data))
				yield break;

			var value = data.Trim();
			if (value == string.Empty)
				yield break;

			var or = -1;//or 标志位置 + =
			var not = -1;//not 标志位置 - !
			var left = -1;//左引号位置
			var right = -1;//右引号位置
			var quote = '\0';//引号类型
			var space = -1;//空格位置
			var last = -1;//最后一次处理位置
			var vln = -1;//值长度
			var count = 0;
			var length = value.Length;
			var cs = value.ToCharArray();
			for (var vi = 0; vi < length; vi++)
			{
				var c = cs[vi];//cp[vi];//
				if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
				{
					if (vi > left && left >= 0 && vi != right + 1)
					{
						if (vln >= 0)
							vln++;
						else
							vln = 0;
						cs[vln] = c;
						continue;
					}

					if (vln >= 0)
					{
						yield return callback(count++, or >= 0 ? 1 : not >= 0 ? -1 : 0, new string(cs, 0, vln + 1), state);//value.Substring(0, vln);//
						or = -1;
						not = -1;
						left = -1;
						right = -1;
						space = vi;
						last = vi;
						vln = -1;
						continue;
					}

					space = vi;
					continue;
				}//space

				if (vi > 0 && vi == right + 1)
				{
					if (vln >= 0)
						vln++;
					else
						vln = 0;
					cs[vln] = quote;
				}
				if (c == '"' || c == '\'')
				{
					if (c == quote && vi > left && left >= 0)
					{
						right = vi;
						continue;
					}

					if (vln < 0)
					{
						left = vi;
						quote = c;
						continue;
					}

					if (vln >= 0)
						vln++;
					else
						vln = 0;
					cs[vln] = c;
					continue;
				}//quote

				if (c == '+' || c == '=')
				{
					if ((space == vi - 1 || (space < 0 && left < 0)) && or < 0 && not < 0)
					{
						or = vi;
						continue;
					}
				}
				else if (c == '-' || c == '!')
				{
					if ((space == vi - 1 || (space < 0 && left < 0)) && or < 0 && not < 0)
					{
						not = vi;
						continue;
					}
				}

				if (vln >= 0)
					vln++;
				else
					vln = 0;
				cs[vln] = c;
			}//foreach c in cs
			if (vln >= 0)
				yield return callback(count++, or >= 0 ? 1 : not >= 0 ? -1 : 0, new string(cs, 0, vln + 1), state);//value.Substring(0, vln);
			yield return callback(int.MinValue, 0, data, state);
		}

		//public static IEnumerable TestSplit(string data)
		//{
		//    var t = TestGet(data);//<string>
		//    return SplitLike(t);
		//}
		//public static TYPE TestGet<TYPE>(TYPE value)
		//{
		//    return value;
		//}
	}
}
